package net.pws.common.security.filter;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.pws.common.util.StringUtils;
import net.pws.common.jackson.JsonUtils;
import net.pws.common.security.PrincipalManagerFactory;
import net.pws.common.security.WebUtils;
import net.pws.common.security.spi.AuthenticateFailedException;
import net.pws.common.security.spi.AuthenticateProvider;
import net.pws.common.security.spi.Principal;

import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.tfs.Licence;
import org.apache.commons.tfs.LicenceFactory;


public class JsonAuthenticateProcessorHandler extends
                                             AbstractAuthenticateFilter {
    
    private static final Log logger = LogFactory.getLog(JsonAuthenticateProcessorHandler.class);
    
    private AuthenticateProvider authenticateProvider;
    
    private ClientVersionProvider clientVersionProvider;
    
    private LoginLogProvider loginLogProvider;
    
    public JsonAuthenticateProcessorHandler() {
        super();
    }
    
    public JsonAuthenticateProcessorHandler(AuthenticateProvider authenticateProvider) {
        super();
        this.authenticateProvider = authenticateProvider;
    }
    
    public AuthenticateProvider getAuthenticateProvider() {
        return authenticateProvider;
    }
    
    public void setAuthenticateProvider(AuthenticateProvider authenticateProvider) {
        this.authenticateProvider = authenticateProvider;
    }
    
    public ClientVersionProvider getClientVersionProvider() {
		return clientVersionProvider;
	}

	public void setClientVersionProvider(ClientVersionProvider clientVersionProvider) {
		this.clientVersionProvider = clientVersionProvider;
	}

	public LoginLogProvider getLoginLogProvider() {
		return loginLogProvider;
	}

	public void setLoginLogProvider(LoginLogProvider loginLogProvider) {
		this.loginLogProvider = loginLogProvider;
	}

	public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException,
                                           ServletException {
        if (!(request instanceof HttpServletRequest)) {
            throw new ServletException("Can only process HttpServletRequest");
        }
        
        if (!(response instanceof HttpServletResponse)) {
            throw new ServletException("Can only process HttpServletResponse");
        }
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        String username = getUserName(httpRequest);
        String password = getPassword(httpRequest);
        String accessType = determineAccessType(httpRequest, "by-web");
        String clientVersion = determineClientVersion(httpRequest);
        try {
        	// verify lcs
        	Licence licence = LicenceFactory.getInstance().getLicence();
			if(!licence.validate()) {
        		throw new AuthenticateFailedException(licence.getErrorMessage());
        	}
			
			// verify client version
			if ("by-mobile".equals(accessType)){
				if (!NumberUtils.isDigits(clientVersion)) {
					throw new AuthenticateFailedException("客户端版本太旧，请升级到最新版本！");
				}
				int remoteVersion = Integer.parseInt(clientVersion);
				if (remoteVersion < clientVersionProvider.getVersion().getMinVersion()) {
					throw new AuthenticateFailedException("客户端版本太旧，请升级到最新版本！");
				}
			}
        	
			// verify username & password
            Principal principal = authenticateProvider.authenticate(username,
                                                                    password);
            if (principal == null || StringUtils.isEmpty(principal.getId())) {
                throw new AuthenticateFailedException("用户名或密码错误！");
            }
            if ("by-mobile".equals(accessType) && !principal.isMobileAccessAllowed()) {
                throw new AuthenticateFailedException("该用户无移动终端访问权限！");
            }
            else if ("by-web".equals(accessType) && !principal.isWebAccessAllowed()) {
                throw new AuthenticateFailedException("该用户无WEB访问权限！");
            }
            else if (!"by-web".equals(accessType) && !"by-mobile".equals(accessType)) {
                throw new AuthenticateFailedException("无法识别的访问类型！");
            }
            
            String token = UUID.randomUUID().toString();
            
            PrincipalManagerFactory.getInstance().put(token, principal);
            saveCookie(httpResponse, AUTH_TOKEN_KEY, token, -1);
            
            if (loginLogProvider != null) {
            	loginLogProvider.log(principal, httpRequest, httpResponse);
            }
            
            WebUtils.renderJson(httpResponse, JsonUtils.succeedJson(principal));
        }
        catch (Exception e) {
            logger.error(e, e);
            WebUtils.renderJson(httpResponse,
                                JsonUtils.failedJson(e.getMessage()));
        }
        
        return;
    }
    
    protected String determineClientVersion(ServletRequest request) {
        return ((HttpServletRequest) request).getHeader("Client-Version");
    }
    
}
